package descentFly.away3D4 {
	import UIAway.uif_view;
	
	import UIFree.FX;
	import UIFree.ObjectEvent;
	import UIFree.uif_Timer;
	
	import UIUtils.uif_util;
	import UIUtils.uif_utilA;
	
	import away3d.cameras.Camera3D;
	import away3d.cameras.lenses.PerspectiveLens;
	import away3d.containers.ObjectContainer3D;
	import away3d.core.base.Object3D;
	import away3d.entities.Mesh;
	import away3d.filters.BloomFilter3D;
	import away3d.filters.MotionBlurFilter3D;
	import away3d.loaders.Loader3D;
	import away3d.materials.BitmapMaterial;
	import away3d.materials.ColorMaterial;
	import away3d.materials.MaterialBase;
	import away3d.materials.methods.FogMethod;
	import away3d.primitives.Sphere;
	import away3d.vf.managers.loadSection;
	
	import descentFly.app.df_events;
	import descentFly.app.radar.df_radarEvent;
	import descentFly.away3D4.Generator.df_doorGenerator;
	import descentFly.away3D4.Generator.df_exitGenerator;
	import descentFly.away3D4.Generator.df_monsterGenerator;
	import descentFly.away3D4.chips.df_chipAway;
	import descentFly.away3D4.chips.df_explodeAnim;
	import descentFly.away3D4.chips.df_monster;
	import descentFly.away3D4.net.df_netSupport;
	import descentFly.chips.df_chip;
	import descentFly.controller.df_robotController;
	import descentFly.controller.myFlyController;
	import descentFly.data.df_chips;
	import descentFly.data.df_fields;
	import descentFly.data.df_netSupports;
	import descentFly.df_player;
	import descentFly.df_space;
	import descentFly.df_spaceObject;
	import descentFly.df_utils;
	import descentFly.server.df_servers;
	import descentFly.weaponts.df_awayWeapont;
	
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Matrix3D;
	import flash.geom.Rectangle;
	import flash.geom.Vector3D;
	import flash.utils.Timer;
	import flash.utils.getTimer;
	
	import jiglib.geometry.JTriangleMesh;
	import jiglib.physics.RigidBody;
	import jiglib.plugin.away3d4.Away3D4Mesh;
	import jiglib.plugin.away3d4.Away3D4Physics;
	
	import space.sp_utils;
	
	public class df_awaySpace extends df_space {
		
		public static const FIELD_FIELDOFVIEW 	: String = 'fieldOfView';
		public static const FIELD_FAR 			: String = 'far';
		public static const FIELD_NEAR 			: String = 'near';
		public static const FIELD_FOG 			: String = 'fog';
		public static const FIELD_COLOR			: String = 'color';
		public static const FIELD_BACKGROUND	: String = 'background';
		public static const FIELD_CLEARENV		: String = 'clearEnv';
		public static const FIELD_NETSUPPORTINDEX	: String = 'netSupportIndex';
		public static const FIELD_GRAVITY			: String = 'gravity';
		
		public static const DEFAULT_DEFAULTOFVIEW 	: Number = 80;
		public static const DEFAULT_FAR 			: Number = 3000;
		public static const DEFAULT_NEAR 			: Number = 5;
		public static const DEFAULT_BACKGROUND		: Number = 0;		
	
		public static const EXPLODE_SHOW	: String = 'EXPLODE_SHOW';
		public static const START_POSITION	: String = 'START_POSITION';
		public static const ENV_MAKE		: String = 'ENV_MAKE';
		public static const GET_PATHPATROL	: String = 'GET_PATHPATROL';
		
		private var _physic			: Away3D4Physics;
		private var _swing			: Number;
		private var _camTo			: Matrix3D;
		private var _transMat		: ColorMaterial;
		private var _ls				: df_loadSection;
		private var _explodes		: Array;
		private var _env			: Loader3D;
		private var _envBody		: Array;
		private var _points			: df_points;
		private var _envMake		: Boolean;
		private var _fog			: FogMethod;
		private var _mb				: MotionBlurFilter3D;
		private var _mbTimer		: Timer;
		private var _dShape			: Sphere;
		private var _prevTimer		: uint;
		private var _netSupports	: Array;		
		
		public function df_awaySpace(a_app: uif_view, a_player: df_player, a_options: Object) {
			super(a_app, a_player, a_options);
			_netSupports = df_netSupports.list;
		}
		
		public function get view(): uif_view {
			return app as uif_view;
		}
		
		public function get transMaterial(): ColorMaterial {
			return _transMat;
		}
		
		public function get physic(): Away3D4Physics {
			return _physic;
		}
		
		public function get myChipAway(): df_chipAway {
			return myChip as df_chipAway;
		}
		
/*		public function setObjects(list: Array): void {
			list.forEach(function(item: Object, i: int, arr: Array): void {
				new (item.Class)(This, item.options);
			});
		}
		
		public function setGenerator(options: Object): void {
			new df_monsterGenerator(this, options);
		}
		
		public function setDoors(options: Object): void {
			new df_doorGenerator(this, options);
		}
		
		public function setExits(options: Object): void {
			new df_exitGenerator(this, options);
		}
		
		public function setBackground(object: Object): void {
			new (object.Class)(this, object.options);
		}*/
		
		public function setExtends(list: Array): void {
			list.forEach(function(item: Object, i: int, arr: Array): void {
				new (item.Class)(This, item.options);
			});
		}
		
		protected function resetPoints(): void {
			if (!_points) _points = new df_points();
			else _points.clear();
		}
		
		public function get points(): df_points {
			return _points;
		}
		
		protected function parseEnv(): void {
			resetPoints();
			var childs: Array = new Array();
			for (var i: int =0; i<_env.numChildren; i++)
				childs.push(_env.getChildAt(i));
			
			childs.forEach(function(elem: ObjectContainer3D, i: int, arr: Array): void {
				if (elem is Mesh) {
					var mesh: Mesh = elem as Mesh;
					if (mesh.originalName.substr(0, 1) == '_') {
						_points.parse(mesh);
						//if (mesh.parent) mesh.parent.removeChild(mesh);
					}
				}
			});
		}
		
		public function updateObjectFromEnv(obj: ObjectContainer3D): void {
			if (_fog && obj) {
				for (var i: int = 0; i<obj.numChildren; i++) {
					var child: Object = obj.getChildAt(i) as Object;
					if (child.hasOwnProperty('material') && child.material.hasOwnProperty('addMethod')) {
						child.material.addMethod(_fog);
					}
					if (child.numChildren > 0) updateObjectFromEnv(child as ObjectContainer3D);
				}
			}			
		}
		
		protected function createEnvElem(mesh: Mesh, initInfo: Object): void {
			var v_envBody: JTriangleMesh = _physic.createMesh(mesh, df_utils.objToPosition(initInfo), 
																df_utils.objToOrientation(initInfo));
			v_envBody.friction 	 	= initInfo[df_fields.FIELD_FRICTION];
			v_envBody.restitution 	= initInfo[df_fields.FIELD_RESTITUTION];
			if (_fog) (mesh.material as BitmapMaterial).addMethod(_fog);
			if (initInfo.alphaBlending) (mesh.material as BitmapMaterial).alphaBlending = true;
			updateObjectFromEnv(mesh);
			_env.addChild(mesh);
			_envBody.push(v_envBody);
			//mesh.parent.removeChild(mesh);
		}
		
		override protected function initEnv(initInfo: Object): void {
/*			var mesh: Mesh = df_MeshHelper.childByName(_env, 'env') as Mesh;
			if (!mesh) mesh = _env.getChildAt(0) as Mesh;*/

			_envBody = new Array();
			_points.forEach(df_points.TYPE_ENV, function(item: Object, i: int): void {
				createEnvElem(item.mesh, initInfo);
			});
			
			view.view.scene.addChild(_env);
			startMyChip();
			
			(camera.lens as PerspectiveLens).fieldOfView = initInfo[FIELD_FIELDOFVIEW];
			camera.lens.far 	= initInfo[FIELD_FAR];
			camera.lens.near 	= initInfo[FIELD_NEAR];
			//camera.transform 	= sp_utils.lookAt(new Vector3D(0, 120, 250), new Vector3D());
			
			view.view.backgroundColor = initInfo[FIELD_BACKGROUND];
			super.initEnv(initInfo);
			
			_envMake = true;
			
			_physic.engine.setGravity(df_utils.toVector(initInfo[FIELD_GRAVITY]));
			
			dispatchEvent(new Event(ENV_MAKE));
		}
		
		protected function startMyChip(): void {
			var sp: Object = _points.nextItemFromType(df_points.TYPE_START);
			var chip: df_chipAway = createChip(player.options.chip, sp.position, sp.orientation, myFlyController);
			camera.position = sp.position; 
			chip.callWaitEvent2(chip.body != null, df_chipAway.SETBODY, function(): void {
				if (!view.renderEnabled) view.dispatchEvent(new ObjectEvent(uif_view.RENDERFREEZE, false));
			});
		}
		
		public function createChip(chipClassIndex		: int, 
									startPosition		: Vector3D,
									startOrientation	: Matrix3D,
								   controllerClass		: Class = null, 
								   controllerOptions	: Object = null): df_chipAway {
			
			var chipObj: Object = df_chips.list[chipClassIndex];
			var chipOptions: Object;
			if (controllerClass != null) {
				chipOptions = uif_util.unionObj(chipObj.options, {
					controller	: {
						Class	: controllerClass,
						options	: controllerOptions
					}
				});
			} else chipOptions = chipObj.options;
			
			var chip: df_chipAway = new (chipObj.Class)(this, chipOptions);
				
			chip.callWaitEvent2(chip.body != null, df_chipAway.SETBODY, function (): void {
				chip.body.currentState.position = startPosition;
				chip.body.setOrientation(startOrientation);
			});
				
			return chip;
		}
		
		public function get camera(): Camera3D {
			return view.view.camera;
		}
		
		override protected function removeEnv():void {
			if (_env) {
				playSound(FIELD_CLEARENV);
				_env.dispose(true);
				_envBody.forEach(function(item: RigidBody, i: int, arr: Array): void {
					physic.removeBody(item);
				});
				if (_fog) _fog.dispose(true);
				
				_envMake 	= false;
				_envBody 	= null;
				_env 		= null;
				_fog		= null;
				resetPoints();
			}
			super.removeEnv();
		}
		
		public function callWaitEnv(func: Function): void {
			function doMake(e: Event): void {
				removeEventListener(ENV_MAKE, doMake);
				func();
			}
			if (!_envMake) addEventListener(ENV_MAKE, doMake);
			else func();
		}
		
		public function get envMake(): Boolean {
			return _envMake;
		}
		
		public function get ls(): df_loadSection {
			return _ls;
		}
		
		public function setEnviroment(item: Object): void {
			sp_utils.checkParam(item, FIELD_FIELDOFVIEW, DEFAULT_DEFAULTOFVIEW);
			sp_utils.checkParam(item, FIELD_FAR, DEFAULT_FAR);
			sp_utils.checkParam(item, FIELD_NEAR, DEFAULT_NEAR);
			sp_utils.checkParam(item, FIELD_BACKGROUND, DEFAULT_BACKGROUND);
			sp_utils.checkParam(item, df_fields.FIELD_RESTITUTION, 0);
			sp_utils.checkParam(item, df_fields.FIELD_FRICTION, 0);
			
			if (item.hasOwnProperty(FIELD_FOG)) {
				_fog = new FogMethod(item[FIELD_FOG][FIELD_NEAR], item[FIELD_FOG][FIELD_COLOR]);
			}
			
			_envMake = false;
			_env 	 = _ls.addLoader3D(item.url);
			
			function doLoadEnv(e: Event): void {
				parseEnv();
				initEnv(item);
				_ls.removeEventListener(loadSection.BEFORECOMPLETE, doLoadEnv);
			}
			_ls.addEventListener(loadSection.BEFORECOMPLETE, doLoadEnv);
		}
		
		public function get env(): Loader3D {
			return _env;
		}
		
		protected function doExplodeShow(e: ObjectEvent): void {
			if (_explodes && (_explodes.length > 0)) {
				var chip: df_chipAway = e.object as df_chipAway;
				if (chip) {
					explodeShow(chip.options.explodeIndex?chip.options.explodeIndex:0, 
								chip.body.currentState.position, 300);
				}
			}
		}
		
		protected function explodeShow(explodeIndex: int, position: Vector3D, size: Number): void {
			var explode: df_explodeAnim = _explodes[explodeIndex];
			
			var mat		: Matrix3D 	= new Matrix3D();
			var scale	: Number	= size/df_explodeAnim.SIZE.x;
			mat.appendScale(scale, scale, scale);
			mat.appendTranslation(position.x, position.y, position.z);
			explode.transform = mat;
			view.view.scene.addChild(explode);
			explode.begin(function(): void {
				view.view.scene.removeChild(explode);
			});
		}
		
		protected function doGetPathPatrol(e: ObjectEvent): void {
			if (_points) {
				var result	: Object;
				var index	: Object;
				if (e.object.hasOwnProperty(df_fields.FIELD_PATHID))
					_points.getItemFromID(e.object[df_fields.FIELD_PATHID], function(a_item: Object): void {
						result = a_item;
					});
				else {
					index = e.object.pathIndex?e.object.pathIndex:0;
					result = _points.forEach(df_points.TYPE_PATH, function(pathItem: Object, i: int): Object {
						return (i == index)?pathItem:null;
					});
				}
				if (result) e.object.result = result.path;
			}
		}
		
		override protected function beginLoadScene(a_scene: Object): void {
			if (!_ls) {
				view.dispatchEvent(new ObjectEvent(uif_view.RENDERFREEZE, true));
				_ls = new df_loadSection();
				super.beginLoadScene(a_scene);
				_ls.endSection(superAfterLoadScene);
			}
		}
		
		public function setExplodes(explodes: Array): void {
			function doLoadFrames(options: Object, a_frames: Array, index: int): void {
				var explode: df_explodeAnim = new df_explodeAnim(This as df_space, a_frames, options);
				_explodes[index] = explode;
			}
			
			_explodes = new Array(explodes.length);
			explodes.forEach(function(item: Object, i: int, arr: Array): void {
				if (item.frames) df_utils.loadFrames(item, doLoadFrames);
				else df_utils.loadFramesOneImage(item, doLoadFrames, i);
			});
		}
		
		protected function superAfterLoadScene(): void {
			_swing  = 0;
			_ls 	= null;
			super.afterLoadScene();
		}
		
		override protected function initialize():void {
			super.initialize();
			_envMake 	= false;
			_camTo 		= new Matrix3D();
			_physic 	= new Away3D4Physics(view.view, 2);
			
			_transMat 	= new ColorMaterial(0x888800);
			_transMat.alpha = 0;
			
			resetPoints();
			
			var rect: Rectangle = view.getInner();
			rect.inflate(-5, -5);
			
			view.app.addEventListener(df_events.SHOW_WINDOW, doShowWindow);
			view.app.addEventListener(df_events.NODIALOGS, doNoDialogs);
			
			view.app.stage.addEventListener(df_events.LOAD_LEVEL, doLoadLevel);
			view.app.stage.addEventListener(df_events.LOAD_ONLINEBATTLE, doLoadOnLineBattle);
			
			/*
			_dShape = new Sphere(new ColorMaterial(0xFFFFFF), 5);
			view.view.scene.addChild(_dShape);
			*/
		}
		
		override protected function listenEvents():void {
			super.listenEvents();
			addEventListener(EXPLODE_SHOW, doExplodeShow);
			addEventListener(GET_PATHPATROL, doGetPathPatrol);
		}
		
		override protected function removeEvents():void {
			super.removeEvents();
			removeEventListener(EXPLODE_SHOW, doExplodeShow);
			removeEventListener(GET_PATHPATROL, doGetPathPatrol);
			view.app.removeEventListener(df_events.SHOW_WINDOW, doShowWindow);
			view.app.removeEventListener(df_events.NODIALOGS, doNoDialogs);
			
			view.app.stage.removeEventListener(df_events.LOAD_LEVEL, doLoadLevel);
			view.app.stage.removeEventListener(df_events.LOAD_ONLINEBATTLE, doLoadOnLineBattle);
		}
		
		protected function doLoadLevel(e: ObjectEvent): void {
			loadScene(e.object);
		}
		
		protected function doLoadOnLineBattle(e: ObjectEvent): void {
			loadOnLineScene(e.object);
		}
		
		protected function loadOnLineScene(onLineBattle: Object): void {
			var index: int = levelIndexFromID(onLineBattle.id);
			if (index > -1) {
				var scene: Object = levels[index];
				loadScene(prepareOnLineLevel(scene, onLineBattle));
			}
		}
		
		protected function prepareOnLineLevel(a_sourceScene: Object, onLineBattle: Object): Object {
			var result: Object = uif_util.union(a_sourceScene, {
				battle_id: onLineBattle.battle_id
			});
			var v_extends: Array = a_sourceScene.Extends?a_sourceScene.Extends:[];
			if (scene.hasOwnProperty(FIELD_NETSUPPORTINDEX) && _netSupports) {
				v_extends = v_extends.concat([
					netSupport(onLineBattle.battle_id)
				]);
			}
			var i: int=0;
			while (i < v_extends.length) {
				if ((v_extends[i].Class == df_monsterGenerator) && 
					(parseInt(onLineBattle.montersIndex) == 0)) {
					v_extends.splice(i, 1);
				} else i++;
			}
			
			result.Extends = v_extends;
			return result;
		}
		
		protected function netSupport(battleID: int): Object {
			return uif_utilA.union(_netSupports[scene.netSupportIndex], {
				options	: {
					socket	: {
						session	: battleID,
						uid		: player.UID
					}
				}
			});
		}
		
		override protected function setDisableScene(set: Boolean): void {
			view.dispatchEvent(new ObjectEvent(uif_view.RENDERFREEZE, set));
			view.stage.dispatchEvent(new ObjectEvent(myFlyController.FREEZEMYCONTROLLER, set));
//			if (myChipAway) myChipAway.noActiveSphere = set;
		}
		
		override public function get disableScene(): Boolean {
			return !view.renderEnabled;
		}
		
		protected function doShowWindow(e: Event): void {
			disableScene = true;
		}
		
		protected function doNoDialogs(e: Event): void {
			disableScene = false;
		}
		
		public function envRayTest(gp1 : Vector3D, gp2: Vector3D): Object {
			for (var i: int=0; i <_envBody.length; i++) {
				var meshEnv: Mesh = (_envBody[i].skin as Away3D4Mesh).mesh;
				var p1: Vector3D = sp_utils.globalToLocal(meshEnv, gp1);
				var p2: Vector3D = sp_utils.globalToLocal(meshEnv, gp2);
				
				var v: Vector3D = df_utils.hitTestSubMesh(meshEnv.subMeshes[0], p1, p2);
				if (v) return {
							hitPoint	: sp_utils.localToGlobal(meshEnv, v),
							mesh		: meshEnv,
							envIndex	: i
						}
			}
			
			return null;
		}
		
		override protected function doMyChipBulletHit(e: Event): void {
/*			var time: Number = 1000 + (1 - myChip.live / myChip.maxLive) * 5000;
			if (!_mbTimer) {
				setMBlur(1);					
				function doMBTimer(): void {
					setMBlur(0);
					_mbTimer = null;
				}
				_mbTimer = new Timer(time, 1);
				_mbTimer.addEventListener(TimerEvent.TIMER_COMPLETE, doMBTimer);
			} else {
				_mbTimer.stop();
				_mbTimer.delay = time;
			}
			_mbTimer.start();*/
		}
		
/*		
		public function setMBlur(a_mblur : Number): void {
			if (a_mblur == 0) view.view.filters3d = [];
			else {
				if (!_mb) _mb = new MotionBlurFilter3D();
				_mb.strength = 0.2;
				view.view.filters3d = [_mb];
			}
		}
*/		
		
		protected function calcCamTo(a_body: RigidBody): Matrix3D {
			var camDistance	: Number = 80;
			var mat			: Matrix3D = a_body.skin.transform.clone();
			var imat		: Matrix3D = mat.clone();
			imat.invert();
			
			var dir			: Vector3D = new Vector3D(0, 0.4, -0.6);
			dir.normalize();
			dir.scaleBy(camDistance * 2);
			dir.x = Math.sin(_swing) * 2;
			
			var p1			: Vector3D = mat.transformVector(new Vector3D());
			var p2			: Vector3D = mat.transformVector(dir);
			
			var result		: Object = envRayTest(p1, p2);

			if (result) {
				dir = imat.transformVector(result.hitPoint);
				//_dShape.position = result.hitPoint;
				
			} else dir = imat.transformVector(p2);
			dir.scaleBy(0.5);
			
			mat.prependTranslation(dir.x, dir.y, dir.z);
			return mat;
		}
		
		override protected function doMyChipDispose(e: Event): void {
			super.doMyChipDispose(e);
			if (envMake) {
				df_spaceObject.oneTimer(3000, function(e: Event): void {
					if (!myChip && envMake) startMyChip();
				});
			}
		}
		
		public function get chipACCEL(): Number {
			return options.chipACCEL;
		}
		
		public function get chipTORMOS(): Number {
			return options.chipTORMOS;
		}
		
		override protected function doRender(e:Event):void {
			if (view.renderEnabled) {
				if (_envMake && myChip && myChipAway.body) {
					_camTo = calcCamTo(myChipAway.body);
				}
				
				_swing += 0.12;
				_physic.step(0.1);
				if (options.CAMBLAND < 1)
					view.view.camera.transform = Matrix3D.interpolate(view.view.camera.transform, _camTo, options.CAMBLAND);
				else view.view.camera.transform = _camTo;
			}
			
/*			
			var curTimer: uint = getTimer();
			if (_prevTimer) {
				if (_cycleTime)
					_cycleTime = (_cycleTime + (curTimer - _prevTimer)) / 2;
				else _cycleTime = curTimer - _prevTimer;
			}
			_prevTimer = curTimer;*/
		}
	}
}